using System;
using System.Collections.Generic;
using System.Linq;
using PhoneBook.Core.Data;
using PhoneBook.Core.Domain.Contacts;
using PhoneBook.Core.Domain.Phones;
using PhoneBook.Core.Domain.UserGroups;

namespace PhoneBook.Service.Contacts
{
    public class ContactService:IContactService
    {


        private IRepository<Contact> _contactRepository;
        private IRepository<UserGroup> _userGroupRepository;
        private IRepository<Phone> _phoneRepository;

        public ContactService(IRepository<Contact> contactRepository, IRepository<UserGroup> userGroupRepository, IRepository<Phone> phoneRepository)
        {
            _contactRepository = contactRepository;
            _userGroupRepository = userGroupRepository;
            _phoneRepository = phoneRepository;
        }

        public IList<Contact> GetContactsByUserGroup(int groupId)
        {

            var query = from c in _contactRepository.Table
                        from g in c.UserGroups
                        where g.Id == groupId
                        select new
                        {

                            UserName = c.UserName,
                            Memo = c.Memo,
                            Phones = (from p in c.Phones where p.IsActive select p),
                            UserGroups = (from ug in c.UserGroups select ug),
                            Id = c.Id
                        };



            var result = query.ToList();

            if (result != null)
            {
                return result.Select(r => new Contact()
                {
                    UserName = r.UserName,
                    Memo = r.Memo,
                    Phones = (from p in r.Phones select p).ToList(),
                    UserGroups = (from ug in r.UserGroups select ug).ToList(),
                    Id = r.Id
                }).ToList();


            }
            else
            {
                return null;
            }
        }

        public void AddContact(Contact contact)
        {
            _contactRepository.Insert(contact);
        }

        public IList<Contact> GetAllContacts()
        {

            var query = from c in _contactRepository.Table
                        select new
                        {

                            UserName = c.UserName,
                            Memo = c.Memo,
                            Phones = (from p in c.Phones where p.IsActive select p),
                            UserGroups = (from ug in c.UserGroups select ug),
                            Id = c.Id
                        };



            var result = query.ToList();

            if (result != null)
            {
                return result.Select(r => new Contact()
                                       {
                                           UserName = r.UserName,
                                           Memo = r.Memo,
                                           Phones = (from p in r.Phones select p).ToList(),
                                           UserGroups = (from ug in r.UserGroups select ug).ToList(),
                                           Id = r.Id
                                       }).ToList();

              
            }
            else
            {
                return null;
            }
        

        }

        public Contact GetContact(int contactId)
        {
            var query = from c in _contactRepository.Table
                        where c.Id == contactId
                        select new 
                                   {

                                      UserName  = c.UserName,
                                      Memo = c.Memo,
                                      Phones = (from p in c.Phones where p.IsActive select p),
                                      UserGroups = (from ug in c.UserGroups select ug),
                                      Id = c.Id
                                   };



            var result =query.SingleOrDefault();
            if(result !=null)
            {
                return new Contact()
                {
                    UserName = result.UserName,
                    Memo = result.Memo,
                    Phones = (from p in result.Phones select p).ToList(),
                    UserGroups = (from ug in result.UserGroups select ug).ToList(),
                    Id = result.Id
                };
            }
            else
            {
                return null;
            }
        


        }

        public void UpdateContact(Contact entity)
        {
            entity.UserGroups.ToList().ForEach(c => c.Contacts.Add(entity));
            _contactRepository.Update(entity);
        }

        public int UpdateContact(int contactId, string name, string memo, IList<int> clientGroupIds, IList<Phone> phones)
        {
            var c = _contactRepository.GetById(contactId);
            c.UserName = name;
            c.Memo = memo;

            var allUserGroups = _userGroupRepository.Table.ToList();


           //client no, server yes, delete 
            var deleteUserGroupIds= c.UserGroups.Where(ug => !clientGroupIds.Contains(ug.Id)).Select(t=>t.Id);
            var deleteUserGroup= allUserGroups.Where(ug => deleteUserGroupIds.Contains(ug.Id)).ToList();
            deleteUserGroup.ForEach(g=>c.UserGroups.Remove(g));


            //client yes,server no , insert 
            if (clientGroupIds != null)
            {
                var insertUserGroupIds = clientGroupIds.Where(ug => !c.UserGroups.Select(t => t.Id).Contains(ug));
                var insertUserGroup = allUserGroups.Where(ug => insertUserGroupIds.Contains(ug.Id)).ToList();
                insertUserGroup.ForEach(c.UserGroups.Add);
            }

            //phone delete then add
            c.Phones.ToList().ForEach(p=>
                                          {
                                              p.IsActive = false;
                                              _phoneRepository.Update(p);
                                          });
            if(phones!= null)
            {
                phones.ToList().ForEach(p=>
                                            {
                                                c.Phones.Add(p);
                                                p.IsActive = true;
                                            });
            }

            _contactRepository.Update(c);
            return c.Id;
        }

        public void DeleteContact(int contactId)
        {
            var entity = _contactRepository.GetById(contactId);

            var phones = entity.Phones;
            if(phones != null)
            {
                foreach(var p in phones)
                {
                    p.IsActive = false;
                    _phoneRepository.Update(p);
                }
            }
            _contactRepository.Delete(entity);
        }

        public IList<Contact> SearchContact(ContactSearchFilter searchFilter)
        {
            if(string.IsNullOrEmpty(searchFilter.ContactName) && string.IsNullOrEmpty(searchFilter.GroupName))
            {
                return null;
            }

            var query = from c in _contactRepository.Table
                        select new
                        {

                            UserName = c.UserName,
                            Memo = c.Memo,
                            Phones = (from p in c.Phones where p.IsActive select p),
                            UserGroups = (from ug in c.UserGroups select ug),
                            Id = c.Id
                        };




            if(!string.IsNullOrEmpty(searchFilter.ContactName))
            {
                query = from t in query where t.UserName.Contains(searchFilter.ContactName) select t;
            }

            if(!string.IsNullOrEmpty(searchFilter.GroupName))
            {
                
                query = from t in query 
                        from g in t.UserGroups
                        where g.GroupName.Contains(searchFilter.GroupName)
                        select t;
            }


            var result = query.ToList();

            if (result != null)
            {
                return result.Select(r => new Contact()
                {
                    UserName = r.UserName,
                    Memo = r.Memo,
                    Phones = (from p in r.Phones select p).ToList(),
                    UserGroups = (from ug in r.UserGroups select ug).ToList(),
                    Id = r.Id
                }).ToList();


            }
            else
            {
                return null;
            }
        
        }
    }
}